package com.gitee.wsl.ext

import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.reflect.KClass

val Throwable.toMessage get() = message  ?: "Something went wrong!"

val Throwable.causes: Sequence<Throwable>
    get() = sequence {
        var subCause = cause
        while (subCause != null) {
            yield(subCause)
            subCause = subCause.cause
        }
    }

fun Throwable.tryUnwrap(kClass: KClass<RuntimeException> = RuntimeException::class): Throwable =
    if (!kClass.isInstance(this)) this else cause ?: this

/**
 * The root cause of this [Throwable], that is,
 * the throwable that was thrown the first.
 */
val Throwable.rootCause: Throwable
    get() {
        var rootCause: Throwable = this
        while (rootCause.cause != null && rootCause.cause !== rootCause) {
            rootCause = rootCause.cause ?: error("Must not happen.")
        }
        return rootCause
    }

/**
 * Prints the stack trace of this [Throwable] and rethrows it.
 *
 * This function can be useful for debugging purposes
 * where you want to log the stack trace before rethrowing an exception.
 *
 * @throws Throwable Always rethrows the original [Throwable] after printing its stack trace.
 */
@OptIn(ExperimentalContracts::class)
fun Throwable.printStackAndThrow(): Nothing {
    contract {
        returns() implies false
    }

    printStackTrace()
    throw this
}


